#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"

PUBLIC int kernel_main()
{
	disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
			 "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");

	int i, j, eflags, prio;
	u8 rpl;
	u8 priv;

	struct task *t;
	struct proc *p = proc_table;
	char* stk = task_stack + STACK_SIZE_TOTAL;
//	u16 selector_ldt = SELECTOR_LDT_FIRST;
//	u8 privilege;
//		u8 rpl;
//	int eflags;
//	int i, j;
//	int prio;
	for (i = 0; i < NR_TASKS + NR_PROCS; i++, p++, t++)
	{
		if (i >= NR_TASKS + NR_NATIVE_PROCS)
		{
			p->p_flags = FREE_SLOT;
			continue;
		}
		if (i < NR_TASKS)
		{
			// TASK
			t = task_table + i;
			priv = PRIVILEGE_TASK;
			rpl = RPL_TASK;
			eflags = 0x1202;
			prio = 15;
		} else
		{
			// USER PROC
			t = user_proc_table + (i - NR_TASKS);
			priv = PRIVILEGE_USER;
			rpl = RPL_USER;
			eflags = 0x202;
			prio = 5;
		}

		strcpy(p -> name, t -> name);
		p->p_parent = NO_TASK;

		if (strcmp(t->name, "INIT") != 0)
		{
			p->ldts[INDEX_LDT_C] = gdt[SELECTOR_KERNEL_CS >> 3];
			p->ldts[INDEX_LDT_RW] = gdt[SELECTOR_KERNEL_DS >> 3];

			p->ldts[INDEX_LDT_C].attr1 = DA_C | priv << 5;
			p->ldts[INDEX_LDT_RW].attr1 = DA_DRW | priv << 5;
		}
		else
		{
			unsigned int k_base;
			unsigned int k_limit;
			int ret = get_kernel_map(&k_base, &k_limit);
			assert(ret == 0);
			init_desc(&p->ldts[INDEX_LDT_C], 0,
					(k_base + k_limit) >> LIMIT_4K_SHIFT,
					DA_32 | DA_LIMIT_4K | DA_C | priv << 5);
			init_desc(&p->ldts[INDEX_LDT_RW],
					0,
					(k_base + k_limit) >> LIMIT_4K_SHIFT,
					DA_32 | DA_LIMIT_4K | DA_DRW | priv << 5);
		}

		p -> regs.cs = INDEX_LDT_C << 3 | SA_TIL | rpl;
		p -> regs.ds =
		p -> regs.es =
		p -> regs.fs =
		p -> regs.ss = INDEX_LDT_RW << 3 | SA_TIL | rpl;
		p -> regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;

		p ->regs.eip = (u32) t -> initial_eip;
		p -> regs.esp = (u32) stk;
		p -> regs.eflags = eflags;

		p->ticks = p->priority = prio;

		p -> p_flags = 0;
		p -> p_msg = 0;
		p -> p_recvfrom = NO_TASK;
		p -> p_sendto = NO_TASK;

		p -> has_int_msg = 0;
		p -> q_sending = 0;
		p -> next_sending = 0;

		for (j = 0; j < NR_FILES; j++)
			p->filp[j] = 0;
		stk -= t->stacksize;
	}

	k_reenter = 0;
	ticks = 0;

	p_proc_ready = proc_table;

	init_clock();

	init_keyboard();

	restart();
	while(1){}
}

PUBLIC int get_ticks()
{
	MESSAGE msg;
	reset_msg(&msg);
	msg.type = GET_TICKS;
	send_recv(BOTH, TASK_SYS, &msg);
	return msg.RETVAL;
}

void Init()
{
	int fd_stdin = open("/dev_tty0", O_RDWR);
	assert(fd_stdin == 0);
	int fd_stdout = open("/dev_tty0", O_RDWR);
	assert(fd_stdout == 1);

	printf("Init() is running ...\n");

	int pid = fork();
	if (pid != 0)
	{
		// parent process
		printf("parent is running, child pid:%d\n", pid);
		int s;
		int child = wait(&s);
		printf("child (%d) exited with status: %d.\n", child, s);
	}
	else
	{
		printf("child is running, pid:%d\n", getpid());
		exit(123);
	}

	while (1) {
		int s;
		int child = wait(&s);
		printf("child (%d) exited with status: %d.\n", child, s);
	}
}

void TestA()
{
	for(;;);
}

void TestB()
{
	for(;;);
}

void TestC()
{
	for(;;);
}


PUBLIC void panic(const char* fmt, ...)
{
	int i;
	char buf[256];

	va_list arg = (va_list) ((char*) &fmt + 4);
	i = vsprintf(buf, fmt, arg);
	printl("%c !!panic!! %s", MAG_CH_PANIC, buf);
	__asm__ __volatile__("ud2");
}
